package com.jse.pay;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.nutz.dao.Dao;
import org.nutz.http.Request;
import org.nutz.http.Sender;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import com.jse.util.IP;
import com.jse.util.WXPayUtil;

@IocBean
public class WxPay {

	Log log = Logs.get();
	
	@Inject
	PropertiesProxy conf;
	
	@Inject
	Dao dao;

	/**
	 * 
	 * @param param title id orderno price openid
	 * @return
	 */
	public Map<Object,Object> getH5(Map<String, Object> data) {
		NutMap param=NutMap.WRAP(data);
		String appid = param.getString("wxpay.appid");
		if(Strings.isEmpty(appid)) {
			appid = conf.get("wxpay.appid");
		}
		String mch_id = param.getString("wxpay.mch_id");// 商户号
		if(Strings.isEmpty(mch_id)) {
			mch_id = conf.get("wxpay.mch_id");// 商户号
		}
		String key = param.getString("wxpay.key");
		if(Strings.isEmpty(key)) {
			key = conf.get("wxpay.key");
		}
		String openid = param.get("openid").toString();// openid 用户微信id
		String body = param.get("title").toString();
		String out_trade_no = param.get("orderno").toString();// 订单号
		String attach = param.get("id").toString();// 附加数据 原样返回
		String totalFee = getMoney(param.get("price").toString());// 总金额以分为单位，不带小数点
		String spbill_create_ip = IP.getIP();// 订单生成的机器 IP
		String notify_url = conf.get("wxpay.notify_url");// 通知
		String trade_type = "JSAPI";
		String nonce_str = WXPayUtil.generateNonceStr();// 随机字符串
		
		try {
			SortedMap<String, String> packageParams = new TreeMap<String, String>();
			packageParams.put("appid", appid);
			packageParams.put("mch_id", mch_id);
			packageParams.put("nonce_str", nonce_str);
			packageParams.put("body", body);
			packageParams.put("attach", attach);
			packageParams.put("out_trade_no", out_trade_no);
			packageParams.put("total_fee", totalFee);
			packageParams.put("spbill_create_ip", spbill_create_ip);
			packageParams.put("notify_url", notify_url);
			packageParams.put("trade_type", trade_type);
			packageParams.put("openid", openid);
			String sign = WXPayUtil.generateSignature(packageParams, key);
			packageParams.put("sign", sign);// 加密
			String requestXML = WXPayUtil.generateSignedXml(packageParams, key);
			log.info("支付请求：" + requestXML);
			String resXml = Sender
					.create(Request.post("https://api.mch.weixin.qq.com/pay/unifiedorder").setData(requestXML)).send()
					.getContent();
			log.info("支付结果：" + resXml);
			Map<String, String> map = WXPayUtil.xmlToMap(resXml);
			SortedMap<Object,Object> ret = new TreeMap<Object,Object>();
			ret.put("appId", appid);
			ret.put("timeStamp", WXPayUtil.getCurrentTimestamp());
			ret.put("nonceStr", map.get("nonce_str"));
			ret.put("package", "prepay_id=" + map.get("prepay_id"));
			ret.put("signType", "MD5");
			String signStr=createSign(ret,key);
			ret.put("paySign", signStr);
			return ret;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 获取扫描支付url
	 * 
	 * @param map{
	 *            title id orderno price
	 *            notify_url 通知地址 product_id 商品id }
	 * @return
	 */
	public String getQrcode(Map<String, Object> param) {
		String appid = conf.get("wxpay.appid");
		String mch_id = conf.get("wxpay.mch_id");// 商户号
		String key = conf.get("wxpay.key");
		String notify_url = conf.get("wxpay.notify_url");// 通知
		String body = param.get("title").toString();
		String out_trade_no = param.get("orderno").toString();// 订单号
		String nonce_str = WXPayUtil.generateNonceStr();// 随机字符串
		String product_id = param.get("id").toString();// 商品id 扫描必填
		String spbill_create_ip = IP.getIP();
		String totalFee = getMoney(param.get("price").toString());// 总金额以分为单位，不带小数点
		try {

			// 正式上线的时候价格根据订单id查询
//			String order_price = "1"; // 价格 注意：价格的单位是分
			
			SortedMap<String, String> packageParams = new TreeMap<String, String>();
			packageParams.put("appid", appid);
			packageParams.put("mch_id", mch_id);
			packageParams.put("nonce_str", nonce_str);
			packageParams.put("body", body);
			packageParams.put("out_trade_no", out_trade_no);
			packageParams.put("total_fee", totalFee);
			packageParams.put("spbill_create_ip", spbill_create_ip);
			packageParams.put("notify_url", notify_url);
			packageParams.put("trade_type", "NATIVE");
			packageParams.put("product_id", product_id);// 商品id
			Calendar nowTime = Calendar.getInstance();
			packageParams.put("time_start", Times.format("yyyyMMddHHmmss", nowTime.getTime()));
			nowTime.add(Calendar.DATE, 1);
			packageParams.put("time_expire", Times.format("yyyyMMddHHmmss", nowTime.getTime()));

			String sign = WXPayUtil.generateSignature(packageParams, key);
			packageParams.put("sign", sign);// 加密

			String requestXML = WXPayUtil.generateSignedXml(packageParams, key);
			log.info("支付请求：" + requestXML);
			String resXml = Sender
					.create(Request.post("https://api.mch.weixin.qq.com/pay/unifiedorder").setData(requestXML)).send()
					.getContent();
			log.info("支付结果：" + resXml);
			Map<String, String> map = WXPayUtil.xmlToMap(resXml);
			// 交易保障
			String codeurl = "";
			if (map.get("return_code").toString().equals("SUCCESS")
					&& map.get("result_code").toString().equals("SUCCESS")) {
				codeurl = map.get("code_url");// 微信二维码短链接

			} else {
				log.info(map.get("err_code_des"));
			}
			return codeurl;
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return "";
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public boolean notify(HashMap tbl) {
		try {
			tbl.put(".table", "wxpay");
			dao.insert(tbl);
		} catch (Exception e) {
			log.error(e);
		}
		try {
			boolean result=tbl.get("return_code").equals("SUCCESS");
			return result;
		} catch (Exception e) {
			log.error(e);
		}
		return false;
	}

	/**
	 * 元转换成分
	 * 
	 * @param money
	 * @return
	 */
	public static String getMoney(String amount) {
		if (amount == null) {
			return "";
		}
		// 金额转化为分为单位
		String currency = amount.replaceAll("\\$|\\￥|\\,", ""); // 处理包含, ￥ 或者$的金额
		int index = currency.indexOf(".");
		int length = currency.length();
		Long amLong = 0l;
		if (index == -1) {
			amLong = Long.valueOf(currency + "00");
		} else if (length - index >= 3) {
			amLong = Long.valueOf((currency.substring(0, index + 3)).replace(".", ""));
		} else if (length - index == 2) {
			amLong = Long.valueOf((currency.substring(0, index + 2)).replace(".", "") + 0);
		} else {
			amLong = Long.valueOf((currency.substring(0, index + 1)).replace(".", "") + "00");
		}
		return amLong.toString();
	}
	
	@SuppressWarnings("rawtypes")
	public static String createSign(SortedMap<Object,Object> parameters,String key){  
        StringBuffer sb = new StringBuffer();  
        Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序（升序）  
        Iterator it = es.iterator();  
        while(it.hasNext()) {  
            Map.Entry entry = (Map.Entry)it.next();  
            String k = (String)entry.getKey();  
            Object v = entry.getValue();  
            if(null != v && !"".equals(v)   
                    && !"sign".equals(k) && !"key".equals(k)) {  
                sb.append(k + "=" + v + "&");  
            }  
        }  
        sb.append("key=" + key);
        String sign = Lang.md5(sb.toString()).toUpperCase();  
        return sign;  
    }
	
	public static void main(String[] args) {
		// 扫码支付
		NutMap data = new NutMap();
		// data.put("wxpay_appid", "wx2787c3302c182d65");
		// data.put("wxpay_mch_id", "1289729501");
		// data.put("wxpay_key", "6e332d87778242619fd832c1bc85d12f");
		// data.put("body","商品信息");
		// data.put("spbill_create_ip","219.142.254.120");
		// data.put("total_fee","100");
		// data.put("device_info", "WEB");
		// data.put("nonce_str",UUID.randomUUID().toString().replace("-", ""));
		// data.put("notify_url", "http://www.iepsy.com/pay/wx_notify");
		// data.put("detail", "商品");
		// data.put("attach", "心教育");
		// data.put("out_trade_no", "17012318170009");
		// data.put("fee_type", "CNY");
		// data.put("total_fee", "60");
		// data.put("product_id", "xxxxx11111");
		// System.err.println(getQrcode(data));

		// 公众号支付
//		data.put("wxpay_appid", "wx2787c3302c182d65");
//		data.put("wxpay_mch_id", "1289729501");
//		data.put("wxpay_key", "6e332d87778242619fd832c1bc85d12f");
//		// data.put("secret", "46d29cfb91416dd55822661840c29d14");
//		data.put("openid", "oHStSs_tYVWk92RMF0w_QwVUjzIg");
//		data.put("body", "商品信息");
//		data.put("spbill_create_ip", "219.142.254.120");
//		data.put("total_fee", "100");
//		data.put("device_info", "WEB");
//		data.put("nonce_str", UUID.randomUUID().toString().replace("-", ""));
//		data.put("notify_url", "http://www.iepsy.com/pay/wx_notify");
//		data.put("detail", "商品");
//		data.put("attach", "心教育");
//		data.put("out_trade_no", "17012318170029");
//		data.put("fee_type", "CNY");
		data.put("total_fee", "60");
		
		System.err.println(IP.getIP());
	}

//字段名	变量名	必填	类型	示例值	描述
//返回状态码	return_code	是	String(16)	SUCCESS	
//SUCCESS/FAIL
//此字段是通信标识，非交易标识，交易是否成功需要查看result_code来判断
//返回信息	return_msg	否	String(128)	签名失败	
//返回信息，如非空，为错误原因
//签名失败
//参数格式校验错误
//以下字段在return_code为SUCCESS的时候有返回
//
//字段名	变量名	必填	类型	示例值	描述
//公众账号ID	appid	是	String(32)	wx8888888888888888	微信分配的公众账号ID（企业号corpid即为此appId）
//商户号	mch_id	是	String(32)	1900000109	微信支付分配的商户号
//设备号	device_info	否	String(32)	013467007045764	微信支付分配的终端设备号，
//随机字符串	nonce_str	是	String(32)	5K8264ILTKCH16CQ2502SI8ZNMTM67VS	随机字符串，不长于32位
//签名	sign	是	String(32)	C380BEC2BFD727A4B6845133519F3AD6	签名，详见签名算法
//签名类型	sign_type	否	String(32)	HMAC-SHA256	签名类型，目前支持HMAC-SHA256和MD5，默认为MD5
//业务结果	result_code	是	String(16)	SUCCESS	SUCCESS/FAIL
//错误代码	err_code	否	String(32)	SYSTEMERROR	错误返回的信息描述
//错误代码描述	err_code_des	否	String(128)	系统错误	错误返回的信息描述
//用户标识	openid	是	String(128)	wxd930ea5d5a258f4f	用户在商户appid下的唯一标识
//是否关注公众账号	is_subscribe	否	String(1)	Y	用户是否关注公众账号，Y-关注，N-未关注，仅在公众账号类型支付有效
//交易类型	trade_type	是	String(16)	JSAPI	JSAPI、NATIVE、APP
//付款银行	bank_type	是	String(16)	CMC	银行类型，采用字符串类型的银行标识，银行类型见银行列表
//订单金额	total_fee	是	Int	100	订单总金额，单位为分
//应结订单金额	settlement_total_fee	否	Int	100	应结订单金额=订单金额-非充值代金券金额，应结订单金额<=订单金额。
//货币种类	fee_type	否	String(8)	CNY	货币类型，符合ISO4217标准的三位字母代码，默认人民币：CNY，其他值列表详见货币类型
//现金支付金额	cash_fee	是	Int	100	现金支付金额订单现金支付金额，详见支付金额
//现金支付货币类型	cash_fee_type	否	String(16)	CNY	货币类型，符合ISO4217标准的三位字母代码，默认人民币：CNY，其他值列表详见货币类型
//总代金券金额	coupon_fee	否	Int	10	代金券金额<=订单金额，订单金额-代金券金额=现金支付金额，详见支付金额
//代金券使用数量	coupon_count	否	Int	1	代金券使用数量
//代金券类型	coupon_type_$n	否	String	CASH	
//CASH--充值代金券 
//NO_CASH---非充值代金券
//并且订单使用了免充值券后有返回（取值：CASH、NO_CASH）。$n为下标,从0开始编号，举例：coupon_type_0
//代金券ID	coupon_id_$n	否	String(20)	10000	代金券ID,$n为下标，从0开始编号
//单个代金券支付金额	coupon_fee_$n	否	Int	100	单个代金券支付金额,$n为下标，从0开始编号
//微信支付订单号	transaction_id	是	String(32)	1217752501201407033233368018	微信支付订单号
//商户订单号	out_trade_no	是	String(32)	1212321211201407033568112322	商户系统内部订单号，要求32个字符内，只能是数字、大小写字母_-|*@ ，且在同一个商户号下唯一。
//商家数据包	attach	否	String(128)	123456	商家数据包，原样返回
//支付完成时间	time_end	是	String(14)	20141030133525	支付完成时间，格式为yyyyMMddHHmmss，如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则

}
